#ifndef _BACKEND_H
#define _BACKEND_H

#include <stdbool.h>
#include "ast.h"
#include "common.h"
#include "container.h"

struct enum_element;
struct enum_basic;
struct enum_combo;
struct type;
struct variable_declaration;
struct event;
struct function;
struct access_table;
struct statement;
struct expression;

/* Enumerate Table */
extern int enum_basic_count;
extern int enum_combo_count;
extern struct enum_basic *enum_basic_table;
extern struct enum_combo *enum_combo_table;
/* Type Table */
extern int type_count;
extern struct type *type_table;
/* Global Variable Table */
extern int global_var_count;
extern struct variable_declaration *global_var_table_dec;
extern struct variable_definition *global_var_table;
/* Event Table */
extern int event_count;
extern struct event *event_table;
/* Function Table */
extern int function_count;
extern struct function *function_table;
/* Runtime Variable Access Table */
extern struct access_table access_table;

void validate(struct translationunit *);

void validate_enumlist(struct e_list *);
int validate_enum_basic_identifier(char *);
int validate_enum_combo_identifier(char *);
void validate_enum_combo_copy_noalloc(int, int *, int *);
void validate_enum_combo_copy(int, int **, int *);
int validate_enum_basic_element(int *, int *, char *);
int validate_enum_combo_index(int, int *);
int validate_type(struct t_type *);
bool validate_type_compatible(int, int);
int validate_type_int();
int validate_type_bool();
int validate_type_enum(char *);
int validate_type_enum_basic_index(int);
int validate_type_enum_combo_index(int);
int validate_type_enum_combo_compoindice(int, int *);
int validate_type_size(int);
struct variable_declaration *validate_varlist(struct v_list *);
void validate_functionlist(struct f_list *);
int validate_event_identifier(char *);
int validate_function_identifier(char *);
struct statement *validate_statementlist(struct s_list *, int, int);
void validate_statement(struct statement *, struct s_statement *, int, int);
void validate_expression(struct expression *, struct x_expression *, int, int);
struct expression *validate_expression_construct(struct x_expression *, int, int);
struct expression *validate_expression_position(struct p_position *, int, int);
struct expression *validate_expression_integer(int);
struct expression *validate_expressionlist(struct x_list *, int, int);

void interpret();

struct variable_definition *allocate_varlist(int, struct variable_declaration *);
void allocate_variable_type(struct variable_definition *, int);
void allocate_variable(struct variable_definition *, struct variable_declaration *);
void call_event(int, struct access_table *, int);
void call_function(int, struct variable_definition *, struct variable_definition *, struct access_table *, int);
void access_variable_content(void **, int *, char *, struct access_table *, int);

#define CONTEXT_NORMAL		0x00000000

#define CONTEXT_FUNCTION	0x00000001
#define CONTEXT_LOOP		0x00000002
#define CONTEXT_G_ENV		0x00000003

#define CONTEXT_LVALUE		0x00000100
#define CONTEXT_RVALUE		0x00000200
#define CONTEXT_G_STORAGE	0x00000300
#define CONTEXT_IMMEDIATE	0x00000400

#define CONTEXT_BOOLEAN		0x00010000
#define CONTEXT_INTEGER		0x00020000	// Intger, For Enum, this will evaluate its Integer Value
#define CONTEXT_ENUM		0x00040000
#define CONTEXT_CONT		0x00080000
#define CONTEXT_ARRAY		0x00100000
#define CONTEXT_INDEX		0x00200000	// Integer, For Enum, this will evaluate its Index Value
#define CONTEXT_G_TYPE		0x003F0000	// Group of type related stuff */

#define CONTEXT_NONZERO		0x01000000
#define CONTEXT_NONNEG		0x02000000
#define CONTEXT_G_SPEC		0x03000000

#define CONTEXT_NOVALUE		0x10000000


/* Runtime Variable Access Table */

struct variable_definition {
	bool owner;

	int type;

	union variable_content {
		struct {
			void *array;
		} array;

		struct {
			struct container *container;
		} container;

		struct {
			int *integer;
		} integer;

		struct {
			bool *boolean;
		} boolean;

		struct {
			int *elemindex;
		} enum_basic;

		struct {
			int *elemindice;
		} enum_combo;
	} spec;
};

struct access_table {
	int count;

	struct access_element {
		union {
			struct {
				int event;
				struct variable_definition *local_table;
			} event;

			struct {
				int function;
				struct variable_definition *return_value;
				struct variable_definition *argument_table;
				struct variable_definition *local_table;
			} function;
		} spec;

		struct access_element *next;
	} *first;
};

/* Enumerate Table */

struct enum_element {
	int enumerate;
	char identifier[T_IDENTIFIER_LEN];
	int index;
	int value;
	char *desc;
};

struct enum_basic {
	char identifier[T_IDENTIFIER_LEN];
	int count;
	struct enum_element *elements;
};

struct enum_combo {
	char identifier[T_IDENTIFIER_LEN];
	int count;
	int compo_count;
	int *components;
};

/* Type Table */

enum type_cate {
	INTEGER,
	BOOLEAN,
	ENUM_BASIC,
	ENUM_COMBO,
	ARRAY_INT,
	ARRAY_ENUM_BASIC,
	ARRAY_ENUM_COMBO,
	CONTAINER
};

struct type {
	enum type_cate cate;
	union {
		struct {
			int enumindex;
		} enum_basic, enum_combo;

		struct {
			int elemtype;
			int size;
		} array_int;

		struct {
			int elemtype;
			int enumindex;
			int size;
		} array_enum_basic;

		struct {
			int elemtype;
			int enumindex;
			int size;
		} array_enum_combo;

		struct {
			int elemtype;
		} container;
	} spec;
};

/* Variable Declaration Table */

struct variable_declaration {
	char identifier[T_IDENTIFIER_LEN];
	int type;
};

/* Event Table */

struct event {
	char identifier[T_IDENTIFIER_LEN];

	int local_count;
	struct variable_declaration *local_table;

	int statement_count;
	struct statement *statement_table;
};

/* Function Table */

struct function {
	char identifier[T_IDENTIFIER_LEN];
	int type;

	int argument_count;
	struct variable_declaration *argument_table;

	int local_count;
	struct variable_declaration *local_table;

	int statement_count;
	struct statement *statement_table;
};

/* Statement Table */

enum statement_cate {
	EXPRESSION,
	IF,
	IF_ELSE,
	WHILE,
	DO_WHILE,
	FOR,
	BREAK,
	CONTINUE,
	RETURN,
	EVENTCALL,
	EVENTTRANS,
	INPUT,
	OUTPUT
};

struct statement {
	enum statement_cate cate;

	union {
		struct {
			struct expression *expression;
		} s_expression, s_return;

		struct {
			struct expression *condition;

			int statement_count;
			struct statement *statement_table;
		} s_if, s_while, s_do_while;

		struct {
			struct expression *condition;

			int truestatement_count;
			struct statement *truestatement_table;

			int falsestatement_count;
			struct statement *falsestatement_table;
		} s_if_else;

		struct {
			struct expression *initialization;
			struct expression *condition;
			struct expression *iteration;

			int statement_count;
			struct statement *statement_table;
		} s_for;

		struct {
			int eventindex;
		} s_eventcall, s_eventtrans;

		struct {
			struct expression *screen;
			struct expression *destination;
		} s_input;

		struct {
			struct expression *screen;
			char *string;
		} s_output;
	} spec;
};

/* Expression */

enum expression_cate {
	ASSIGN,

	FUNCCALL,

	IDENTIFIER,
	ARRAYELEM,
	IMMEDIATE_INT,
	IMMEDIATE_BOOL,

	LOGICAL_NOT,
	LOGICAL_AND,
	LOGICAL_OR,

	COMPARE_EQ,
	COMPARE_NE,
	COMPARE_LT,
	COMPARE_LE,
	COMPARE_GT,
	COMPARE_GE,

	NUMERIC_ADD,
	NUMERIC_SUB,
	NUMERIC_MUL,
	NUMERIC_DIV,
	NUMERIC_MOD,
	NUMERIC_LINC,
	NUMERIC_LDEC,
	NUMERIC_LSUB,
	NUMERIC_RINC,
	NUMERIC_RDEC,

	CONDITIONAL,

	ENUM_RANDOM,
	ENUM_VALUE,
	ENUM_EXTRACT,
	ENUM_COMBINE,

	CONT_SIZE,
	CONT_FILL,
	CONT_SHUFFLE,
	CONT_PEEK,
	CONT_REMOVE,
	CONT_INSERT,
};

struct expression {
	enum expression_cate cate;
	int type;

	union {
		struct {
			int functionindex, argument_count;
			struct expression *argument_table;
		} funccall;

		struct {
			char *identifier;
			struct expression *index;
		} array;

		struct {
			char *identifier;
		} identifier;

		struct {
			int value;
		} immediate_int, immediate_bool;

		struct {
			struct expression *expression;
		} logical_not, numeric_linc, numeric_ldec, numeric_lsub, numeric_rinc, numeric_rdec, enum_value, cont_size, cont_fill, cont_shuffle;

		struct {
			struct expression *first, *second;
		} assign, logical_and, logical_or, compare_eq, compare_ne, compare_lt, compare_le, compare_gt, compare_ge, numeric_add, numeric_sub, numeric_mul, numeric_div, numeric_mod, enum_extract;

		struct {
			struct expression *condition, *truevalue, *falsevalue;
		} conditional;

		struct {
			enum type_cate enumcate;	/* ENUM_BASIC or ENUM_COMBO */
			int enumindex;
		} enum_random;

		struct {
			int component_count;
			struct expression *component_table;
		} enum_combine;

		struct {
			struct expression *container;
			struct expression *position;	/* top = 0, bottom = -1, random = -2 */
		} cont_peek, cont_remove;

		struct {
			struct expression *container, *element;
			struct expression *position;	/* top = 0, bottom = -1, random = -2 */
		} cont_insert;
	} spec;
};

#endif
